home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume18 / vtree < prev    next >
Encoding:
Internet Message Format  |  1989-04-19  |  35.1 KB

  1. Subject:  v18i105:  Visual directory browser
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: ispi!jbayer@uunet.uu.net
  7. Posting-number: Volume 18, Issue 105
  8. Archive-name: 
  9.  
  10. This is the second release of the VTREE (please pronounce this V-TREE, for
  11. "visual files") program.  The program is designed to show the layout of a
  12. directory tree or filesystem.  It has options to show the amount of
  13. storage being taken up in each directory, count the number of inodes,
  14. etc.
  15.  
  16. It works on SCO Xenix, BSD, SystemV, Version 7, etc.  This release also
  17. includes a variety of output-formatting options.
  18.  
  19. Jonathan  Bayer
  20. Intelligent Software Products, Inc.
  21.  
  22.  
  23. #! /bin/sh
  24. # This is a shell archive.  Remove anything before this line, then unpack
  25. # it by saving it into a file and typing "sh file".  To overwrite existing
  26. # files, type "sh file -c".  You can also feed this as standard input via
  27. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  28. # will see the following message at the end:
  29. #        "End of shell archive."
  30. # Contents:  Makefile README customize.h direct.c hash.c hash.h
  31. #   patchlevel.h vtree.1 vtree.c
  32. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  33. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  34.   echo shar: Will not clobber existing file \"'Makefile'\"
  35. else
  36. echo shar: Extracting \"'Makefile'\" \(2465 characters\)
  37. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  38. X#    Build VTREE
  39. X#
  40. X#    Define the type of system we're working with.  Three
  41. X# choices:
  42. X#
  43. X#   1.    BSD Unix 4.2 or 4.3.  Directory read support in the
  44. X# standard library, so we don't have to do much.  Select BSD.
  45. X#
  46. X#   2.    System V.  I depend on Doug Gwyn's directory reading
  47. X# routines.  They were posted to Usenet "comp.sources" early in
  48. X# May 1987.  They're worth the effort to get, if you don't have
  49. X# them already.  Select SYS_V.  Be sure to define NLIB to be the
  50. X# 'cc' option to include the directory library.
  51. X#
  52. X#   3.  System III, or machines without any directory read
  53. X# packages.  I have a minimal kludge.  Select SYS_III.
  54. X#
  55. X#   4.  SCO Xenix 386.  See the comments for System V.
  56. X#
  57. X#   5.  SCO Xenix 286.  See the comments for System V.
  58. X#
  59. X
  60. X# Case 1:
  61. X#VTREE=vtree
  62. X#SYS=    -DBSD
  63. X#NLIB=    -lgetopt
  64. X
  65. X# Case 2:
  66. X#VTREE=vtree
  67. X#SYS=    -DSYS_V
  68. X#NLIB=    -lndir
  69. X
  70. X# Case 3:
  71. X#VTREE=vtree
  72. X#SYS=    -DSYS_III
  73. X#NLIB=
  74. X
  75. X# Case 4: sco Xenix-386
  76. XVTREE=vtree
  77. XSYS=    -Ox -CSON -DSCO_XENIX 
  78. XNLIB=    -lmalloc -lx
  79. X
  80. X# Case 5: sco Xenix-286
  81. X#VTREE=vtreeL
  82. X#SYS=    -Ox -CSON -DSCO_XENIX  -DMEMORY_BASED -Ml2 -F 8000
  83. X#NLIB=    -lmalloc -lx
  84. X
  85. X
  86. X#    Standard things you may wish to change:
  87. X#
  88. X#    INSTALL        directory to install vtree in
  89. X
  90. XINSTALL    =    /usr/local/bin
  91. X
  92. X#    MANDIR        manual page directoryr
  93. X#            (the .L is used on Xenix systems.  Other systems will
  94. X#            be different)
  95. X
  96. XMANDIR =    /u/man/man.L
  97. X
  98. X#    MANEND        end of man page file name
  99. X
  100. XMANEND =    L
  101. X
  102. X#    The following OPTIONS may be defined:
  103. X#
  104. X#    LSTAT        we have the lstat(2) system call (BSD only)
  105. X#    HSTATS        print hashing statistics at end of run
  106. X#    ONEPERLINE    On the first line only, if there are more than
  107. X#            one directory listed, print it on a line by itself
  108. X#            and print the last subdirectory on the first line
  109. X#            of the tree
  110. X#    MEMORY_BASED    Keep the tree structure in memory for added speed.
  111. X#
  112. X#    Compile time options:
  113. X
  114. XOPTIONS    = -DMEMORY_BASED
  115. X
  116. X#  END OF USER-DEFINED OPTIONS
  117. X
  118. X
  119. XCFLAGS=    -O $(SYS) $(OPTIONS)
  120. XSRCS=        vtree.c    hash.c    direct.c    \
  121. X        hash.h    customize.h    patchlevel.h
  122. XOBJS=        vtree.o    hash.o
  123. X
  124. X$(VTREE):        $(OBJS)
  125. X        $(CC) -o $(VTREE) $(CFLAGS) $(OBJS) $(NLIB)
  126. X
  127. Xinstall:    $(VTREE)
  128. X        cp $(VTREE) $(INSTALL)
  129. X        cp vtree.1 $(MANDIR)/vtree.$(MANEND)
  130. X#        chown local $(INSTALL)/$(VTREE)
  131. X#        chgrp pd $(INSTALL)/$(VTREE)
  132. X#        chmod 755 $(INSTALL)/$(VTREE)
  133. X
  134. Xclean:
  135. X        rm -f $(OBJS) $(VTREE)
  136. X
  137. Xvtree.o:    vtree.c direct.c hash.h customize.h patchlevel.h
  138. X
  139. Xhash.o:        hash.c hash.h customize.h patchlevel.h
  140. X
  141. Xshar:        ;
  142. X        rm -f *.o vtree *- vtree.shr
  143. X        shar * >/tmp/vtree.shr
  144. X        mv /tmp/vtree.shr .
  145. X
  146. END_OF_FILE
  147. if test 2465 -ne `wc -c <'Makefile'`; then
  148.     echo shar: \"'Makefile'\" unpacked with wrong size!
  149. fi
  150. # end of 'Makefile'
  151. fi
  152. if test -f 'README' -a "${1}" != "-c" ; then 
  153.   echo shar: Will not clobber existing file \"'README'\"
  154. else
  155. echo shar: Extracting \"'README'\" \(4068 characters\)
  156. sed "s/^X//" >'README' <<'END_OF_FILE'
  157. X*****************************************************************************
  158. X
  159. X    To compile vtree examine the makefile and set the appropiate options.
  160. X
  161. X    type "make" to compile it, and "make install" to install it.
  162. X
  163. X*****************************************************************************
  164. X
  165. XVtree version 1.1 notes
  166. X
  167. XThe following changes were made:
  168. X
  169. X** Patches were received from the following people:
  170. X**
  171. X**    1.    Mike Howard, (...!uunet!milhow1!how)
  172. X**        Mike's patches included changes to the Makefile to
  173. X**        customize vtree to SCO Xenix for the 286 as well as the
  174. X**        386.  He also added external definitions to hash.c
  175. X**
  176. X**    2.    Andrew Weeks, (...!uunet!mcvax!doc.ic.ac.uk!aw)
  177. X**        Andrew sent me diffs to make vtree work properly under BSD
  178. X**        He also pointed out that you will need one of the PD getopt
  179. X**        packages for BSD.
  180. X**
  181. X**    3.    Ralph Chapman, (...uunet!ihnp4!ihuxy!chapman)
  182. X**        Ralph sent me changes (not diffs unfortunately) to make
  183. X**        vtree work properly under the SYS_III option.  His changes
  184. X**        were in direct.c and vtree.c
  185. X**
  186. X**    4.    David Eckelkamp notified me of a bug when printing the
  187. X**        visual tree.  The bug occured when a directory name
  188. X**        was too long.  It caused vtree to mess up the tree
  189. X**        being printed.
  190. X
  191. X
  192. X    The vtree program can now be compiled in a memory-based
  193. Xversion. This option will force vtree to read an entire directory
  194. Xbefore doing anything with it.  This will prevent vtree from reading a
  195. Xdirectory 2 times for certain operations.  Strangely enough, the
  196. Xmemory-based version doesn't seem to be much faster than the disk-based
  197. Xversion.  If anybody has any suggestions as to why I would appreciate
  198. Xthem.
  199. X
  200. X    A minor compile-time option has been added to control the format
  201. Xof the first line.  If specified, then vtree checks the first line to
  202. Xmake sure it is only one directory name (no "/"s).  If not then vtree
  203. Xwill print the first line by itself, and then print the LAST subdir on
  204. Xthe next line to begin the tree.
  205. X
  206. X    Two new runtime options have been added. The "-o" option will now
  207. Xsort the directories before processing them.  It is only available with
  208. Xthe memory-based version of the program.  The "-f" option specifies
  209. Xfloating column widths.  The width of each column will be only as wide
  210. Xas necessary.
  211. X
  212. X    The visual display has been cleaned up a bit.
  213. X
  214. X*****
  215. X
  216. X    I did the development for vtree on an SCO Xenix 386 system. 
  217. XThe System III  routines and the BSD routines are untested by myself. 
  218. XBased on the replies I received from Andrew Weeks and Ralph Chapman it
  219. Xshould compile and execute on those systems.  If you have to make any
  220. Xlocal modifications to the program to make it work I would appreciate
  221. Xhearing about them so I can keep the program up to date.
  222. X
  223. X
  224. X
  225. XJonathan B. Bayer
  226. XIntelligent Software Products, Inc.
  227. XRockville Centre, NY   11570
  228. XPhone: (516) 766-2867
  229. Xusenet:    uunet!ispi!root
  230. X
  231. X
  232. X*****************************************************************************
  233. XVtree version 1.0 notes
  234. X
  235. X    This is the first release of the VTREE (please pronounce this
  236. XV-TREE, for "visual files") program.  The program is designed to show
  237. Xthe layout of a directory tree or filesystem.  It has options to show
  238. Xthe amount of storage being taken up in each directory, count the number
  239. Xof inodes, etc.
  240. X
  241. X    VTREE is dependent on the UCB directory reading routines. 
  242. XPublic-domain routines for System V have been released to the Usenet
  243. X(comp.sources.unix) by Doug Gwyn (gwyn@brl.mil).  If you don't have
  244. Xthem, they're worth your trouble to get.  Still, you may be able to use
  245. Xthe System III configuration of the Makefile as a stopgap measure. 
  246. X
  247. X
  248. X    The program was originally the program AGEF, written by David S.
  249. XHayes.  As it stands now the hashing routines are untouched by myself,
  250. Xbut most of the rest of the program is different.  The System III
  251. Xroutines are also his.
  252. X
  253. X
  254. X    I hope this program will be useful to you.  If you find bugs in
  255. Xit or have any suggestions for improvements, I'd like to hear about
  256. Xthem.
  257. X
  258. XJonathan B. Bayer
  259. XIntelligent Software Products, Inc.
  260. XRockville Centre, NY   11570
  261. XPhone: (516) 766-2867
  262. Xusenet:    uunet!ispi!root
  263. X
  264. END_OF_FILE
  265. if test 4068 -ne `wc -c <'README'`; then
  266.     echo shar: \"'README'\" unpacked with wrong size!
  267. fi
  268. # end of 'README'
  269. fi
  270. if test -f 'customize.h' -a "${1}" != "-c" ; then 
  271.   echo shar: Will not clobber existing file \"'customize.h'\"
  272. else
  273. echo shar: Extracting \"'customize.h'\" \(951 characters\)
  274. sed "s/^X//" >'customize.h' <<'END_OF_FILE'
  275. X/* 
  276. X   This is the customizations file.  It changes our ideas of
  277. X   how to read directories.
  278. X*/
  279. X
  280. X#define NAMELEN    512        /* max size of a full pathname */
  281. X
  282. X#ifdef BSD
  283. X#    include        <sys/dir.h>
  284. X#    define    OPEN    DIR
  285. X#    define    READ    struct direct
  286. X#    define    NAME(x)    ((x).d_name)
  287. X#endif
  288. X
  289. X#ifdef SCO_XENIX
  290. X#    include <sys/ndir.h>
  291. X#    define    OPEN    DIR
  292. X#    define    READ    struct direct
  293. X#    define    NAME(x)    ((x).d_name)
  294. X#endif
  295. X
  296. X#ifdef SYS_V
  297. X /* Customize this.  This is part of Doug Gwyn's package for */
  298. X /* reading directories.  If you've put this file somewhere */
  299. X /* else, edit the next line. */
  300. X
  301. X#    include        <sys/dirent.h>
  302. X
  303. X#    define    OPEN    struct direct
  304. X#    define    READ    struct dirent
  305. X#    define    NAME(x)    ((x).d_name)
  306. X#endif
  307. X
  308. X#ifdef SYS_III
  309. X#    define    OPEN    FILE
  310. X#    define    READ    struct direct
  311. X#    define    NAME(x)    ((x).d_name)
  312. X#    define    INO(x)    ((x).d_ino)
  313. X
  314. X#    include        "direct.c"
  315. X
  316. X#endif
  317. X
  318. X#if !(defined(BSD) || !defined(SYS_V) || !defined(SYS_III) || !defined(SCO_XENIX))
  319. X"This is an Error"
  320. X#endif
  321. END_OF_FILE
  322. if test 951 -ne `wc -c <'customize.h'`; then
  323.     echo shar: \"'customize.h'\" unpacked with wrong size!
  324. fi
  325. # end of 'customize.h'
  326. fi
  327. if test -f 'direct.c' -a "${1}" != "-c" ; then 
  328.   echo shar: Will not clobber existing file \"'direct.c'\"
  329. else
  330. echo shar: Extracting \"'direct.c'\" \(1051 characters\)
  331. sed "s/^X//" >'direct.c' <<'END_OF_FILE'
  332. X/* direct.c
  333. X  
  334. X   SCCS ID    @(#)direct.c    1.6    7/9/87
  335. X  
  336. X *
  337. X *    My own substitution for the berkeley reading routines,
  338. X *    for use on System III machines that don't have any other
  339. X *    alternative.
  340. X */
  341. X
  342. X#define NAMELENGTH    14
  343. X#ifdef    SYS_III
  344. X    FILE    *opendir(name)    { return (fopen(name,"r") ); }
  345. X#else
  346. X    #define opendir(name)    fopen(name, "r")
  347. X#endif
  348. X#define closedir(fp)    fclose(fp)
  349. X
  350. Xstruct dir_entry {        /* What the system uses internally. */
  351. X    ino_t           d_ino;
  352. X    char            d_name[NAMELENGTH];
  353. X};
  354. X
  355. Xstruct direct {            /* What these routines return. */
  356. X    ino_t           d_ino;
  357. X    char            d_name[NAMELENGTH];
  358. X    char            terminator;
  359. X};
  360. X
  361. X
  362. X /*
  363. X  * Read a directory, returning the next (non-empty) slot. 
  364. X  */
  365. X
  366. XREAD           *
  367. Xreaddir(dp)
  368. X    OPEN           *dp;
  369. X{
  370. X    static READ     direct;
  371. X
  372. X    /* This read depends on direct being similar to dir_entry. */
  373. X
  374. X    while (fread(&direct, sizeof(struct dir_entry), 1, dp) != 0) {
  375. X    direct.terminator = '\0';
  376. X    if (INO(direct) != 0)
  377. X        return &direct;
  378. X    };
  379. X
  380. X    return (READ *) NULL;
  381. X}
  382. END_OF_FILE
  383. if test 1051 -ne `wc -c <'direct.c'`; then
  384.     echo shar: \"'direct.c'\" unpacked with wrong size!
  385. fi
  386. # end of 'direct.c'
  387. fi
  388. if test -f 'hash.c' -a "${1}" != "-c" ; then 
  389.   echo shar: Will not clobber existing file \"'hash.c'\"
  390. else
  391. echo shar: Extracting \"'hash.c'\" \(4504 characters\)
  392. sed "s/^X//" >'hash.c' <<'END_OF_FILE'
  393. X/* hash.c
  394. X  
  395. X   SCCS ID    @(#)hash.c    1.6    7/9/87
  396. X  
  397. X * Hash table routines for AGEF.  These routines keep the program from
  398. X * counting the same inode twice.  This can happen in the case of a
  399. X * file with multiple links, as in a news article posted to several
  400. X * groups.  The use of a hashing scheme was suggested by Anders
  401. X * Andersson of Uppsala University, Sweden.  (enea!kuling!andersa) 
  402. X */
  403. X
  404. X/* hash.c change history:
  405. X 28 March 1987        David S. Hayes (merlin@hqda-ai.UUCP)
  406. X    Initial version.
  407. X*/
  408. X
  409. X#include <stdio.h>
  410. X#include <sys/types.h>
  411. X#include "hash.h"
  412. X
  413. Xstatic struct htable *tables[TABLES];
  414. Xextern char *malloc();        /* added 6/17/88 */
  415. Xextern char *realloc();        /* added 6/17/88 */
  416. Xextern char *calloc();        /* added 6/17/88 */
  417. X
  418. X/* These are for statistical use later on. */
  419. Xstatic int      hs_tables = 0,    /* number of tables allocated */
  420. X                hs_duplicates = 0,    /* number of OLD's returned */
  421. X                hs_buckets = 0,    /* number of buckets allocated */
  422. X                hs_extensions = 0,    /* number of bucket extensions */
  423. X                hs_searches = 0,/* number of searches */
  424. X                hs_compares = 0,/* total key comparisons */
  425. X                hs_longsearch = 0;    /* longest search */
  426. X
  427. X
  428. X /*
  429. X  * This routine takes in a device/inode, and tells whether it's been
  430. X  * entered in the table before.  If it hasn't, then the inode is added
  431. X  * to the table.  A separate table is maintained for each major device
  432. X  * number, so separate file systems each have their own table. 
  433. X  */
  434. X
  435. Xh_enter(dev, ino)
  436. X    dev_t           dev;
  437. X    ino_t           ino;
  438. X{
  439. X    static struct htable *tablep = (struct htable *) 0;
  440. X    register struct hbucket *bucketp;
  441. X    register ino_t *keyp;
  442. X    int             i;
  443. X
  444. X    hs_searches++;        /* stat, total number of calls */
  445. X
  446. X    /*
  447. X     * Find the hash table for this device. We keep the table pointer
  448. X     * around between calls to h_enter, so that we don't have to locate
  449. X     * the correct hash table every time we're called.  I don't expect
  450. X     * to jump from device to device very often. 
  451. X     */
  452. X    if (!tablep || tablep->device != dev) {
  453. X    for (i = 0; tables[i] && tables[i]->device != dev;)
  454. X        i++;
  455. X    if (!tables[i]) {
  456. X        tables[i] = (struct htable *)  malloc(sizeof(struct htable));
  457. X        if (tables[i] == NULL) {
  458. X        perror("can't malloc hash table");
  459. X        return NEW;
  460. X        };
  461. X#ifdef BSD
  462. X        bzero(tables[i], sizeof(struct htable)); 
  463. X#else
  464. X        memset((char *) tables[i], '\0', sizeof (struct htable));
  465. X#endif
  466. X        tables[i]->device = dev;
  467. X        hs_tables++;    /* stat, new table allocated */
  468. X    };
  469. X    tablep = tables[i];
  470. X    };
  471. X
  472. X    /* Which bucket is this inode assigned to? */
  473. X    bucketp = &tablep->buckets[ino % BUCKETS];
  474. X
  475. X    /*
  476. X     * Now check the key list for that bucket.  Just a simple linear
  477. X     * search. 
  478. X     */
  479. X    keyp = bucketp->keys;
  480. X    for (i = 0; i < bucketp->filled && *keyp != ino;)
  481. X    i++, keyp++;
  482. X
  483. X    hs_compares += i + 1;    /* stat, total key comparisons */
  484. X
  485. X    if (i && *keyp == ino) {
  486. X    hs_duplicates++;    /* stat, duplicate inodes */
  487. X    return OLD;
  488. X    };
  489. X
  490. X    /* Longest search.  Only new entries could be the longest. */
  491. X    if (bucketp->filled >= hs_longsearch)
  492. X    hs_longsearch = bucketp->filled + 1;
  493. X
  494. X    /* Make room at the end of the bucket's key list. */
  495. X    if (bucketp->filled == bucketp->length) {
  496. X    /* No room, extend the key list. */
  497. X    if (!bucketp->length) {
  498. X        bucketp->keys = (ino_t *) calloc(EXTEND, sizeof(ino_t));
  499. X        if (bucketp->keys == NULL) {
  500. X        perror("can't malloc hash bucket");
  501. X        return NEW;
  502. X        };
  503. X        hs_buckets++;
  504. X    } else {
  505. X        bucketp->keys = (ino_t *)
  506. X        realloc(bucketp->keys,
  507. X            (EXTEND + bucketp->length) * sizeof(ino_t));
  508. X        if (bucketp->keys == NULL) {
  509. X        perror("can't extend hash bucket");
  510. X        return NEW;
  511. X        };
  512. X        hs_extensions++;
  513. X    };
  514. X    bucketp->length += EXTEND;
  515. X    };
  516. X
  517. X    bucketp->keys[++(bucketp->filled)] = ino;
  518. X    return NEW;
  519. X}
  520. X
  521. X
  522. X /* Buffer statistics functions.  Print 'em out. */
  523. X
  524. X#ifdef HSTATS
  525. Xvoid
  526. Xh_stats()
  527. X{
  528. X    fprintf(stderr, "\nHash table management statistics:\n");
  529. X    fprintf(stderr, "  Tables allocated: %d\n", hs_tables);
  530. X    fprintf(stderr, "  Buckets used: %d\n", hs_buckets);
  531. X    fprintf(stderr, "  Bucket extensions: %d\n\n", hs_extensions);
  532. X    fprintf(stderr, "  Total searches: %d\n", hs_searches);
  533. X    fprintf(stderr, "  Duplicate keys found: %d\n", hs_duplicates);
  534. X    if (hs_searches)
  535. X    fprintf(stderr, "  Average key search: %d\n",
  536. X        hs_compares / hs_searches);
  537. X    fprintf(stderr, "  Longest key search: %d\n", hs_longsearch);
  538. X    fflush(stderr);
  539. X}
  540. X
  541. X#endif
  542. END_OF_FILE
  543. if test 4504 -ne `wc -c <'hash.c'`; then
  544.     echo shar: \"'hash.c'\" unpacked with wrong size!
  545. fi
  546. # end of 'hash.c'
  547. fi
  548. if test -f 'hash.h' -a "${1}" != "-c" ; then 
  549.   echo shar: Will not clobber existing file \"'hash.h'\"
  550. else
  551. echo shar: Extracting \"'hash.h'\" \(625 characters\)
  552. sed "s/^X//" >'hash.h' <<'END_OF_FILE'
  553. X/* Defines for the agef hashing functions.
  554. X
  555. X   SCCS ID    @(#)hash.h    1.6    7/9/87
  556. X */
  557. X
  558. X#define BUCKETS        257    /* buckets per hash table */
  559. X#define TABLES        50    /* hash tables */
  560. X#define EXTEND        100    /* how much space to add to a bucket */
  561. X
  562. Xstruct hbucket {
  563. X    int             length;    /* key space allocated */
  564. X    int             filled;    /* key space used */
  565. X    ino_t          *keys;
  566. X};
  567. X
  568. Xstruct htable {
  569. X    dev_t           device;    /* device this table is for */
  570. X    struct hbucket  buckets[BUCKETS];    /* the buckets of the table */
  571. X};
  572. X
  573. X#define OLD    0        /* inode was in hash already */
  574. X#define NEW    1        /* inode has been added to hash */
  575. END_OF_FILE
  576. if test 625 -ne `wc -c <'hash.h'`; then
  577.     echo shar: \"'hash.h'\" unpacked with wrong size!
  578. fi
  579. # end of 'hash.h'
  580. fi
  581. if test -f 'patchlevel.h' -a "${1}" != "-c" ; then 
  582.   echo shar: Will not clobber existing file \"'patchlevel.h'\"
  583. else
  584. echo shar: Extracting \"'patchlevel.h'\" \(99 characters\)
  585. sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
  586. X/*
  587. X**
  588. X** Patchlevel for VTREE
  589. X**
  590. X*/
  591. X
  592. X#define PATCHLEVEL     V1.2
  593. X#define    VERSION        "VTREE    1.2    9/17/88"
  594. END_OF_FILE
  595. if test 99 -ne `wc -c <'patchlevel.h'`; then
  596.     echo shar: \"'patchlevel.h'\" unpacked with wrong size!
  597. fi
  598. # end of 'patchlevel.h'
  599. fi
  600. if test -f 'vtree.1' -a "${1}" != "-c" ; then 
  601.   echo shar: Will not clobber existing file \"'vtree.1'\"
  602. else
  603. echo shar: Extracting \"'vtree.1'\" \(1803 characters\)
  604. sed "s/^X//" >'vtree.1' <<'END_OF_FILE'
  605. X.TH VTREE 1 local
  606. X.SH NAME
  607. Xvtree \- print a visual tree of a directory structure
  608. X.SH SYNOPSIS
  609. X.B vtree
  610. X[ \-d ] [ \-f ] [ \-h # ] [ \-i ] [ \-o ] [ \-s ] [ \-q ] [ \-v ] [ \-V ] 
  611. X.SH DESCRIPTION
  612. X.IP 
  613. XVtree is a program which scans directories/filesystems and displays the structure on the
  614. Xstandard output.   Normally it will ignore duplicate inodes.
  615. X.IP "\-d "
  616. XInstructs the program to include the duplicate inodes in the totals.
  617. X.PP
  618. X.IP "\-f "
  619. XSpecifies floating column widths.  The widths of each column will be as narrow
  620. Xas possible to conserve space.
  621. X.PP
  622. X.IP "\-h #"
  623. XSpecifies how many levels down to display.
  624. X.PP
  625. X.IP \-i 
  626. Xdisplays the number of inodes (excluding directories) in each directory 
  627. X.PP
  628. X.IP \-o
  629. Xcauses vtree to sort the directories before processing.  It is only
  630. Xavailable for the memory-based version.  Use the "-V" option to find out
  631. Xwhat version you are running.
  632. X.PP
  633. X.IP \-s 
  634. XInstructs the program to continue counting inodes and file sizes when it
  635. Xhas exceeded the levels specified.
  636. X.PP
  637. X.IP \-t 
  638. XDisplays totals at the end of the report
  639. X.PP
  640. X.IP \-q
  641. XQuick display.  No totals of any kind are kept.
  642. X.PP
  643. X.IP \-v
  644. XVisual display.  Normally the program displays one directory on a line,
  645. Xindenting lines to indicate subdirectories.  The visual display builds
  646. Xa tree on the screen showing the actual directory structure.  This method
  647. Xof display excludes any totals other than the final totals.
  648. X.PP
  649. X.IP \-V
  650. XShows current version.  Specifying 2 Vs (-VV) will also show all options in
  651. Xforce.
  652. X.SH AUTHOR
  653. XJonathan B. Bayer
  654. X.PP
  655. XIntelligent Software Products, Inc.
  656. X.PP
  657. XRockville Centre, NY   11570
  658. X.SH ACKNOWLEDGMENTS
  659. XThe program uses the directory routines written and released to the
  660. Xpublic domain by Doug Gwyn.
  661. XThe program is originally based on a program called AGEF written by
  662. XDavid S. Hayes.
  663. END_OF_FILE
  664. if test 1803 -ne `wc -c <'vtree.1'`; then
  665.     echo shar: \"'vtree.1'\" unpacked with wrong size!
  666. fi
  667. # end of 'vtree.1'
  668. fi
  669. if test -f 'vtree.c' -a "${1}" != "-c" ; then 
  670.   echo shar: Will not clobber existing file \"'vtree.c'\"
  671. else
  672. echo shar: Extracting \"'vtree.c'\" \(14873 characters\)
  673. sed "s/^X//" >'vtree.c' <<'END_OF_FILE'
  674. X/* vtree
  675. X  
  676. X   +=======================================+
  677. X   | This program is in the public domain. |
  678. X   +=======================================+
  679. X  
  680. X   This program shows the directory structure of a filesystem or 
  681. X   part of one.  It also shows the amount of space taken up by files
  682. X   in each subdirectory. 
  683. X  
  684. X   Call via
  685. X  
  686. X    vtree fn1 fn2 fn3 ...
  687. X  
  688. X   If any of the given filenames is a directory (the usual case),
  689. X   vtree will recursively descend into it, and the output line will
  690. X   reflect the accumulated totals for all files in the directory.
  691. X   
  692. X   This program is based upon "agef" written by David S. Hayes at the 
  693. X   Army Artificial Intelligence Center at the Pentagon.
  694. X   
  695. X   This program is dependent upon the new directory routines written by
  696. X   Douglas A. Gwyn at the US Army Ballistic Research Laboratory at the
  697. X   Aberdeen Proving Ground in Maryland.
  698. X*/
  699. X/*
  700. X** Patches were received from the following people:
  701. X**
  702. X**    1.    Mike Howard, (...!uunet!milhow1!how)
  703. X**        Mike's patches included changes to the Makefile to
  704. X**        customize vtree to SCO Xenix for the 286 as well as the
  705. X**        386.  He also added external definitions to hash.c
  706. X**
  707. X**    2.    Andrew Weeks, (...!uunet!mcvax!doc.ic.ac.uk!aw)
  708. X**        Andrew sent me diffs to make vtree work properly under BSD
  709. X**        He also pointed out that you will need one of the PD getopt
  710. X**        packages for BSD.
  711. X**
  712. X**    3.    Ralph Chapman, (...uunet!ihnp4!ihuxy!chapman)
  713. X**        Ralph sent me changes (not diffs unfortunately) to make
  714. X**        vtree work properly under the SYS_III option.  His changes
  715. X**        were in direct.c and vtree.c
  716. X**
  717. X**    4.    David Eckelkamp notified me of a bug when printing the
  718. X**        visual tree.  The bug occured when a directory name
  719. X**        was too long.  It caused vtree to mess up the tree
  720. X**        being printed.
  721. X*/
  722. X
  723. X#include "patchlevel.h"
  724. X
  725. X#include <ctype.h>
  726. X#include <sys/types.h>
  727. X#include <sys/stat.h>
  728. X#include <sys/param.h>
  729. X#include <stdio.h>
  730. X#ifdef    BSD
  731. X#include <strings.h>
  732. X#else
  733. X#include <string.h>
  734. X#endif
  735. X
  736. X#include "customize.h"
  737. X#include "hash.h"
  738. X
  739. X
  740. X#ifdef    SYS_III
  741. X    #define    rewinddir(fp)    rewind(fp)
  742. X#endif
  743. X
  744. X#define SAME        0    /* for strcmp */
  745. X#define BLOCKSIZE    512    /* size of a disk block */
  746. X
  747. X#define K(x)        ((x + 1023)/1024)    /* convert stat(2) blocks into
  748. X                     * k's.  On my machine, a block
  749. X                     * is 512 bytes. */
  750. X
  751. X#define    TRUE    1
  752. X#define    FALSE    0
  753. X#define    V_CHAR    "|"    /*    Vertical character    */
  754. X#define    H_CHAR    "-"    /*    Horizontal character    */
  755. X#define    A_CHAR    ">"    /*    Arrow char        */
  756. X#define    T_CHAR    "+"    /*    Tee char        */
  757. X#define    L_CHAR    "\\"    /*    L char, bottom of a branch    */
  758. X
  759. X#define    MAX_COL_WIDTH    15
  760. X#define    MAX_V_DEPTH    256        /* max depth for visual display */
  761. X
  762. X#ifdef    MEMORY_BASED
  763. Xstruct RD_list {
  764. X    READ        entry;
  765. X    struct RD_list    *fptr;
  766. X    struct RD_list    *bptr;
  767. X};
  768. X#endif
  769. X
  770. X
  771. X
  772. Xint        indent = 0,        /* current indent */
  773. X        depth = 9999,        /* max depth */
  774. X        cur_depth = 0,    
  775. X        sum = FALSE,        /* sum the subdirectories */
  776. X        dup = FALSE,        /* use duplicate inodes */
  777. X        floating = FALSE,    /* floating column widths */
  778. X        sort = FALSE,
  779. X        cnt_inodes = FALSE,    /* count inodes */
  780. X        quick = FALSE,        /* quick display */
  781. X        visual = FALSE,        /* visual display */
  782. X        version = 0,        /* = 1 display version, = 2 show options */
  783. X        sub_dirs[MAX_V_DEPTH],
  784. X        sub_dirs_indents[MAX_V_DEPTH];
  785. X
  786. Xstruct    stat    stb;            /* Normally not a good idea, but */
  787. X                    /* this structure is used through- */
  788. X                    /* out the program           */
  789. X
  790. Xextern char    *optarg;            /* from getopt(3) */
  791. Xextern int      optind,
  792. X                opterr;
  793. X
  794. X
  795. Xchar           *Program;        /* our name */
  796. Xshort           sw_follow_links = 1;    /* follow symbolic links */
  797. Xshort           sw_summary;        /* print Grand Total line */
  798. X
  799. Xint             total_inodes, inodes;    /* inode count */
  800. Xlong            total_sizes, sizes;    /* block count */
  801. X
  802. Xchar            topdir[NAMELEN];    /* our starting directory */
  803. X
  804. X
  805. X
  806. X/*
  807. X** Find the last field of a string.
  808. X*/
  809. Xchar *lastfield(p,c)
  810. Xchar *p;    /* Null-terminated string to scan */
  811. Xint   c;    /* Separator char, usually '/' */
  812. X{
  813. Xchar *r;
  814. X
  815. X    r = p;
  816. X    while (*p)            /* Find the last field of the name */
  817. X        if (*p++ == c)
  818. X            r = p;
  819. X    return r;
  820. X} /* lastfield */
  821. X
  822. X
  823. X
  824. X
  825. X /*
  826. X  * We ran into a subdirectory.  Go down into it, and read everything
  827. X  * in there. 
  828. X  */
  829. Xint    indented = FALSE;    /* These had to be global since they */
  830. Xint    last_indent = 0;    /* determine what gets displayed during */
  831. Xint    last_subdir = FALSE;    /* the visual display */
  832. X
  833. X
  834. X
  835. Xdown(subdir)
  836. Xchar    *subdir;
  837. X{
  838. XOPEN    *dp;            /* stream from a directory */
  839. XOPEN    *opendir ();
  840. Xchar    cwd[NAMELEN], tmp[NAMELEN];
  841. Xchar    *sptr;
  842. XREAD    *file;            /* directory entry */
  843. XREAD    *readdir ();
  844. Xint    i, x;
  845. Xstruct    stat    stb;
  846. X
  847. X#ifdef    MEMORY_BASED
  848. Xstruct RD_list    *head = NULL, *tail, *tmp_RD, *tmp1_RD;        /* head and tail of directory list */
  849. Xstruct RD_list    sz;
  850. XREAD        tmp_entry;
  851. X#endif
  852. X
  853. X    if ( (cur_depth == depth) && (!sum) )
  854. X        return;
  855. X
  856. X/* display the tree */
  857. X
  858. X    if (cur_depth < depth) {
  859. X        if (visual) {
  860. X            if (!indented) {
  861. X                for (i = 1; i <cur_depth; i++) {
  862. X                    if (floating) x = sub_dirs_indents[i] + 1;
  863. X                        else x = MAX_COL_WIDTH - 3;
  864. X                    if (sub_dirs[i]) {
  865. X                        printf("%*s%s   ",x - 1," ",V_CHAR);
  866. X                    } else printf("%*s   ",x," ");
  867. X                }
  868. X                if (cur_depth>0) {
  869. X                    if (floating) x = sub_dirs_indents[cur_depth] + 1;
  870. X                        else x = MAX_COL_WIDTH - 3;
  871. X                    if (sub_dirs[cur_depth] == 0) {
  872. X                        printf("%*s%s%s%s ",x - 1," ",L_CHAR,H_CHAR,A_CHAR);
  873. X                        last_subdir = cur_depth;
  874. X                    }
  875. X                    else printf("%*s%s%s%s ",x - 1," ",T_CHAR,H_CHAR,A_CHAR);
  876. X                }
  877. X            } else {
  878. X                if (!floating)
  879. X                    for (i = 1; i<MAX_COL_WIDTH-last_indent-3; i++)
  880. X                        printf("%s",H_CHAR);
  881. X                printf("%s%s%s ",T_CHAR,H_CHAR,A_CHAR);
  882. X            }
  883. X
  884. X    /* This is in case a subdir name is too big.  It is then displayed on
  885. X    ** two lines, the first line is the full name, the second line is
  886. X    ** truncated.  Any subdirs displayed for the current subdir will be
  887. X    ** appended to the second line.  This keeps the columns in order
  888. X    */
  889. X
  890. X#ifndef    ONEPERLINE
  891. X            if (  ( strlen(subdir) > MAX_COL_WIDTH - 3 && !floating )    ) {
  892. X#else
  893. X            if (  ( strlen(subdir) > MAX_COL_WIDTH - 3 && !floating ) ||
  894. X                lastfield(subdir,'/') != subdir) {
  895. X#endif
  896. X
  897. X                printf("%s\n",subdir);
  898. X                for (i = 1; i <=cur_depth; i++) {
  899. X                    if (sub_dirs[i]) {
  900. X                        printf("%*s%s   ",MAX_COL_WIDTH-4," ",V_CHAR);
  901. X                    }
  902. X                    else printf("%*s   ",MAX_COL_WIDTH-3," ");
  903. X                }
  904. X                strcpy(tmp,lastfield(subdir,'/'));
  905. X                tmp[MAX_COL_WIDTH - 4] = 0;
  906. X                printf("%s",tmp);
  907. X#ifdef    ONEPERLINE
  908. X                if (floating || strlen(tmp) < MAX_COL_WIDTH - 4) printf(" ");
  909. X#endif
  910. X                sub_dirs_indents[cur_depth + 1] = last_indent = strlen(tmp) + 1;
  911. X            }
  912. X            else {
  913. X                printf("%s",subdir);
  914. X                sub_dirs_indents[cur_depth + 1] = last_indent = strlen(subdir)+1;
  915. X                if (floating || strlen(subdir) < MAX_COL_WIDTH - 4) 
  916. X                    printf(" ");
  917. X            }
  918. X            indented = TRUE;
  919. X        }
  920. X        else printf("%*s%s",indent," ",subdir);
  921. X    }
  922. X
  923. X/* open subdirectory */
  924. X
  925. X    if ((dp = opendir(subdir)) == NULL) {
  926. X        printf(" - can't read %s\n", subdir);
  927. X        indented = FALSE;
  928. X        return;
  929. X    }
  930. X
  931. X    cur_depth++;
  932. X    indent+=3;
  933. X
  934. X#ifdef BSD
  935. X    getwd(cwd);                /* remember where we are */
  936. X#else
  937. X    getcwd(cwd, sizeof(cwd));        /* remember where we are */
  938. X#endif
  939. X    chdir(subdir);                /* go into subdir */
  940. X
  941. X
  942. X#ifdef    MEMORY_BASED
  943. X
  944. X    for (file = readdir(dp); file != NULL; file = readdir(dp)) {
  945. X        if ((!quick && !visual ) ||
  946. X             ( strcmp(NAME(*file), "..") != SAME &&
  947. X             strcmp(NAME(*file), ".") != SAME &&
  948. X             chk_4_dir(NAME(*file)) ) ) {
  949. X            tmp_RD = (struct RD_list *) malloc(sizeof(sz));
  950. X            memcpy(&tmp_RD->entry, file, sizeof(tmp_entry));
  951. X            tmp_RD->bptr = head;
  952. X            tmp_RD->fptr = NULL;
  953. X            if (head == NULL) head = tmp_RD;
  954. X                else tail->fptr = tmp_RD;
  955. X            tail = tmp_RD;
  956. X        }
  957. X    }
  958. X
  959. X                /* screwy, inefficient, bubble sort    */
  960. X                /* but it works                */
  961. X    if (sort) {
  962. X        tmp_RD = head;
  963. X        while (tmp_RD) {
  964. X            tmp1_RD = tmp_RD->fptr;
  965. X            while (tmp1_RD) {
  966. X                if (strcmp(NAME(tmp_RD->entry), NAME(tmp1_RD->entry)) >0) {
  967. X                    /* swap the two */
  968. X                    memcpy(&tmp_entry, &tmp_RD->entry, sizeof(tmp_entry));
  969. X                    memcpy(&tmp_RD->entry, &tmp1_RD->entry, sizeof(tmp_entry));
  970. X                    memcpy(&tmp1_RD->entry, &tmp_entry, sizeof(tmp_entry));
  971. X                }
  972. X                tmp1_RD = tmp1_RD->fptr;
  973. X            }
  974. X            tmp_RD = tmp_RD->fptr;
  975. X        }
  976. X    }
  977. X
  978. X#endif
  979. X
  980. X    if ( (!quick) && (!visual) ) {
  981. X
  982. X        /* accumulate total sizes and inodes in current directory */
  983. X
  984. X
  985. X#ifdef    MEMORY_BASED
  986. X        tmp_RD = head;
  987. X        while (tmp_RD) {
  988. X            file = &tmp_RD->entry;
  989. X            tmp_RD = tmp_RD->fptr;
  990. X#else
  991. X        
  992. X        for (file = readdir(dp); file != NULL; file = readdir(dp)) {
  993. X#endif
  994. X            if (strcmp(NAME(*file), "..") != SAME) 
  995. X                get_data(NAME(*file),FALSE);
  996. X        }
  997. X
  998. X        if (cur_depth<depth) {
  999. X            if (cnt_inodes) printf("   %d",inodes);
  1000. X            printf(" : %ld\n",sizes);
  1001. X            total_sizes += sizes;
  1002. X            total_inodes += inodes;
  1003. X            sizes = 0;
  1004. X            inodes = 0;
  1005. X        }
  1006. X#ifndef    MEMORY_BASED
  1007. X        rewinddir(dp);
  1008. X#endif
  1009. X    } else if (!visual) printf("\n");
  1010. X
  1011. X    if (visual) {
  1012. X
  1013. X/* count subdirectories */
  1014. X
  1015. X
  1016. X#ifdef    MEMORY_BASED
  1017. X        tmp_RD = head;
  1018. X        while (tmp_RD) {
  1019. X            file = &tmp_RD->entry;
  1020. X            tmp_RD = tmp_RD->fptr;
  1021. X#else
  1022. X        for (file = readdir(dp); file != NULL; file = readdir(dp)) {
  1023. X            if ( (strcmp(NAME(*file), "..") != SAME) &&
  1024. X                 (strcmp(NAME(*file), ".") != SAME) ) {
  1025. X                if (chk_4_dir(NAME(*file))) {
  1026. X#endif
  1027. X                    sub_dirs[cur_depth]++;
  1028. X#ifndef    MEMORY_BASED
  1029. X                }
  1030. X            }
  1031. X#endif
  1032. X        }
  1033. X#ifndef    MEMORY_BASED
  1034. X        rewinddir(dp);
  1035. X#endif
  1036. X    }
  1037. X    
  1038. X/* go down into the subdirectory */
  1039. X
  1040. X#ifdef    MEMORY_BASED
  1041. X    tmp_RD = head;
  1042. X    while (tmp_RD) {
  1043. X        file = &tmp_RD->entry;
  1044. X        tmp_RD = tmp_RD->fptr;
  1045. X#else
  1046. X    for (file = readdir(dp); file != NULL; file = readdir(dp)) {
  1047. X#endif
  1048. X        if ( (strcmp(NAME(*file), "..") != SAME) &&
  1049. X             (strcmp(NAME(*file), ".") != SAME) ) {
  1050. X            if (chk_4_dir(NAME(*file))) 
  1051. X                sub_dirs[cur_depth]--;
  1052. X            get_data(NAME(*file),TRUE);
  1053. X        }
  1054. X    }
  1055. X
  1056. X    if ( (!quick) && (!visual) ) {
  1057. X
  1058. X/* print totals */
  1059. X
  1060. X        if (cur_depth == depth) {
  1061. X            if (cnt_inodes) printf("   %d",inodes);
  1062. X            printf(" : %ld\n",sizes);
  1063. X            total_sizes += sizes;
  1064. X            total_inodes += inodes;
  1065. X            sizes = 0;
  1066. X            inodes = 0;
  1067. X        }
  1068. X    }
  1069. X
  1070. X#ifdef    MEMORY_BASED
  1071. X                /* free the allocated memory */
  1072. X    tmp_RD = head;
  1073. X    while (tmp_RD) {
  1074. X        tmp_RD = tmp_RD->fptr;
  1075. X        free(head);
  1076. X        head = tmp_RD;
  1077. X    }
  1078. X#endif    
  1079. X
  1080. X    if (visual && indented) {
  1081. X        printf("\n");
  1082. X        indented = FALSE;
  1083. X        if (last_subdir>=cur_depth-1) {
  1084. X            for (i = 1; i <cur_depth; i++) {
  1085. X                if (sub_dirs[i]) {
  1086. X                    if (floating)
  1087. X                        printf("%*s%s   ",sub_dirs_indents[i]," ",V_CHAR);
  1088. X                    else printf("%*s%s   ",MAX_COL_WIDTH-4," ",V_CHAR);
  1089. X                } else {
  1090. X                    if (floating)
  1091. X/*ZZZ*/                        printf("%*s   ",sub_dirs_indents[i] + 1," ");
  1092. X                     else printf("%*s   ",MAX_COL_WIDTH-3," ");
  1093. X                 }
  1094. X            }
  1095. X            printf("\n");
  1096. X            last_subdir = FALSE;
  1097. X        }
  1098. X    }
  1099. X    indent-=3;
  1100. X    sub_dirs[cur_depth] = 0;
  1101. X    cur_depth--;
  1102. X
  1103. X    chdir(cwd);            /* go back where we were */
  1104. X    closedir(dp);            /* shut down the directory */
  1105. X
  1106. X
  1107. X} /* down */
  1108. X
  1109. X
  1110. X
  1111. Xint    chk_4_dir(path)
  1112. Xchar    *path;
  1113. X{
  1114. X    if (is_directory(path)) return TRUE;
  1115. X    else return FALSE;
  1116. X        
  1117. X} /* chk_4_dir */
  1118. X
  1119. X
  1120. X
  1121. X/* Is the specified path a directory ? */
  1122. X
  1123. Xint    is_directory(path)
  1124. Xchar           *path;
  1125. X{
  1126. X
  1127. X#ifdef LSTAT
  1128. X    if (sw_follow_links)
  1129. X        stat(path, &stb);    /* follows symbolic links */
  1130. X    else
  1131. X        lstat(path, &stb);    /* doesn't follow symbolic links */
  1132. X#else
  1133. X    stat(path, &stb);
  1134. X#endif
  1135. X
  1136. X    if ((stb.st_mode & S_IFMT) == S_IFDIR)
  1137. X        return TRUE;
  1138. X    else return FALSE;
  1139. X} /* is_directory */
  1140. X
  1141. X
  1142. X
  1143. X /*
  1144. X  * Get the aged data on a file whose name is given.  If the file is a
  1145. X  * directory, go down into it, and get the data from all files inside. 
  1146. X  */
  1147. X
  1148. Xget_data(path,cont)
  1149. Xchar           *path;
  1150. Xint        cont;    
  1151. X{
  1152. X/* struct    stat    stb; */
  1153. Xint        i;
  1154. X
  1155. X    if (cont) { 
  1156. X        if (is_directory(path)) 
  1157. X            down(path);
  1158. X    }
  1159. X    else {
  1160. X        if (is_directory(path)) return;
  1161. X
  1162. X            /* Don't do it again if we've already done it once. */
  1163. X
  1164. X        if ( (h_enter(stb.st_dev, stb.st_ino) == OLD) && (!dup) )
  1165. X            return;
  1166. X        inodes++;
  1167. X        sizes+= K(stb.st_size);
  1168. X    }
  1169. X} /* get_data */
  1170. X
  1171. X
  1172. X
  1173. Xmain(argc, argv)
  1174. Xint    argc;
  1175. Xchar    *argv[];
  1176. X{
  1177. Xint    i,
  1178. X    j,
  1179. X    err = FALSE;
  1180. Xint    option;
  1181. Xint    user_file_list_supplied = 0;
  1182. X
  1183. X    Program = *argv;        /* save our name for error messages */
  1184. X
  1185. X    /* Pick up options from command line */
  1186. X
  1187. X    while ((option = getopt(argc, argv, "dfh:iostqvV")) != EOF) {
  1188. X        switch (option) {
  1189. X            case 'f':    floating = TRUE; break;
  1190. X            case 'h':    depth = atoi(optarg);
  1191. X                    while (*optarg) {
  1192. X                        if (!isdigit(*optarg)) {
  1193. X                            err = TRUE;
  1194. X                            break;
  1195. X                        }
  1196. X                        optarg++;
  1197. X                    }
  1198. X                    break;
  1199. X            case 'd':    dup = TRUE;
  1200. X                    break;    
  1201. X            case 'i':    cnt_inodes = TRUE;
  1202. X                    break;
  1203. X            case 'o':    sort = TRUE; break;    
  1204. X            case 's':    sum = TRUE;
  1205. X                    break;
  1206. X            case 't':    sw_summary = TRUE;
  1207. X                    break;
  1208. X            case 'q':    quick = TRUE;
  1209. X                    dup = FALSE;
  1210. X                    sum = FALSE;
  1211. X                    cnt_inodes = FALSE;
  1212. X                    break;
  1213. X            case 'v':    visual = TRUE;
  1214. X                    break;
  1215. X            case 'V':    version++;
  1216. X                    break;
  1217. X            default:    err = TRUE;
  1218. X        }
  1219. X        if (err) {
  1220. X            fprintf(stderr,"%s: [ -d ] [ -h # ] [ -i ] [ -o ] [ -s ] [ -q ] [ -v ] [ -V ]\n",Program);
  1221. X            fprintf(stderr,"    -d    count duplicate inodes\n");
  1222. X            fprintf(stderr,"    -f    floating column widths\n");
  1223. X            fprintf(stderr,"    -h #    height of tree to look at\n");
  1224. X            fprintf(stderr,"    -i    count inodes\n");
  1225. X            fprintf(stderr,"    -o    sort directories before processing\n");
  1226. X            fprintf(stderr,"    -s    include subdirectories not shown due to -h option\n");
  1227. X            fprintf(stderr,"    -t    totals at the end\n");
  1228. X            fprintf(stderr,"    -q    quick display, no counts\n");
  1229. X            fprintf(stderr,"    -v    visual display\n");
  1230. X            fprintf(stderr,"    -V    show current version\n");
  1231. X            fprintf(stderr,"        (2 Vs shows specified options)\n");
  1232. X            exit(-1);
  1233. X        }
  1234. X    
  1235. X    }
  1236. X
  1237. X    if (version > 0 ) {
  1238. X
  1239. X#ifdef    MEMORY_BASED
  1240. X        printf("%s memory based\n",VERSION);
  1241. X#else
  1242. X        printf("%s disk based\n",VERSION);
  1243. X#endif
  1244. X
  1245. X        if (version>1) {
  1246. X            printf("Tree height:    %d\n",depth);
  1247. X            if (dup) printf("Include duplicate inodes\n");
  1248. X            if (cnt_inodes) printf("Count inodes\n");
  1249. X            if (sum) printf("Include unseen subdirectories in totals\n");
  1250. X            if (sw_summary) printf("Print totals at end\n");
  1251. X            if (quick) printf("Quick display only\n");
  1252. X            if (visual) printf("Visual tree\n");
  1253. X            if (sort) printf("Sort directories before processing\n");
  1254. X        }
  1255. X    }
  1256. X    
  1257. X    /* If user didn't specify targets, inspect current directory. */
  1258. X
  1259. X    if (optind >= argc) {
  1260. X        user_file_list_supplied = 0;
  1261. X    } else {
  1262. X        user_file_list_supplied = 1;
  1263. X    }
  1264. X
  1265. X#ifdef BSD
  1266. X    getwd(topdir);                /* find out where we are */
  1267. X#else
  1268. X    getcwd(topdir, sizeof (topdir));    /* find out where we are */
  1269. X#endif
  1270. X
  1271. X    /* Zero out grand totals */
  1272. X    total_inodes = total_sizes = 0;
  1273. X    /* Zero out sub_dirs */
  1274. X    for (i=0; i<=MAX_V_DEPTH; i++) {
  1275. X        sub_dirs[i] = 0;
  1276. X        sub_dirs_indents[i] = 0;
  1277. X    }
  1278. X        
  1279. X    /* Inspect each argument */
  1280. X    for (i = optind; i < argc || (!user_file_list_supplied && i == argc); i++) {
  1281. X        cur_depth = inodes = sizes = 0;
  1282. X
  1283. X        chdir(topdir);        /* be sure to start from the same place */
  1284. X        get_data(user_file_list_supplied?argv[i] : topdir, TRUE);/* this may change our cwd */
  1285. X
  1286. X        total_inodes += inodes;
  1287. X        total_sizes += sizes;
  1288. X    }
  1289. X
  1290. X    if (sw_summary) {
  1291. X        printf("\n\nTotal space used: %ld\n",total_sizes);
  1292. X        if (cnt_inodes) printf("Total inodes: %d\n",inodes);
  1293. X    }
  1294. X    
  1295. X#ifdef HSTATS
  1296. X    fflush(stdout);
  1297. X    h_stats();
  1298. X#endif
  1299. X
  1300. X    exit(0);
  1301. X} /* main */
  1302. X
  1303. X
  1304. END_OF_FILE
  1305. if test 14873 -ne `wc -c <'vtree.c'`; then
  1306.     echo shar: \"'vtree.c'\" unpacked with wrong size!
  1307. fi
  1308. # end of 'vtree.c'
  1309. fi
  1310. echo shar: End of shell archive.
  1311. exit 0
  1312.  
  1313.  
  1314.